package panel.role.texturejsonedit;

import com.alibaba.fastjson2.JSON;
import com.plealog.genericapp.api.EZEnvironment;
import model.MaterialJson;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.swingx.JXLabel;
import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.JXTextField;
import session.BaseSession;
import session.RoleSession;
import util.MaterialDataUtil;

import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import java.awt.event.ItemEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 材质类型配置面板
 * 功能：
 * <ol>
 *     <li>正则表达式匹配材质类型名</li>
 *     <li>替换材质类型名</li>
 *     <li>修改Unk18</li>
 * </ol>
 */
public class MaterialTypeConfigurePanel extends JPanel {
	private JTextField materialFileField = new JXTextField("material文件路径");
	private JButton materialFileButton = new JButton("选择");
	private JFileChooser fileChooser = new JFileChooser();
	private boolean isUpdated = true; //material文件路径数据是否已经更新，如果需要更新列表数据，则为true，如果与列表数据同步，则为false
	private List<MaterialJson> materialJsons;

	private JTextField reField = new JXTextField("正则表达式匹配纹理名");
	private JButton reButton = new JButton("匹配"); //list呈现匹配结果

	private JCheckBox replaceAllCheckBox = new JCheckBox();
	private JXLabel replaceAllLabel = new JXLabel("新材质类型名");
	private JTextField replaceAllField = new JXTextField("输入新的材质类型(MTD)");
	private JButton okButton = new JButton("执行操作"); //替换匹配到的内容

	private JCheckBox setUnk18CheckBox = new JCheckBox();
	private JXLabel setUnk18Label = new JXLabel("设置Unk18唯一");

	private JXList materialTypeList;//呈现匹配结果，支持编辑
	private DefaultListModel<String> listModel;

	private JButton saveButton = new JButton("保存结果到本地"); //弹出保存对话框

	public MaterialTypeConfigurePanel() {
		setLayout(new MigLayout("wrap 2", "grow"));

		initLayout();
		initListener();
	}

	private void initLayout() {
		JXLabel materialFileLabel = new JXLabel("材质文件");
		JXLabel reLabel = new JXLabel("正则表达式");

		materialFileField.setColumns(30);
		materialFileField.setText(RoleSession.MATERIAL_PATH);
		reField.setColumns(30);
		reField.setToolTipText("输入正则表达式匹配纹理名");
		replaceAllCheckBox.setSelected(true);
		replaceAllField.setToolTipText("以.mtd结尾");
		setUnk18CheckBox.setSelected(true);
		replaceAllField.setColumns(30);
		reButton.setToolTipText("将匹配到的材质名呈现在列表中");

		setUnk18Label.setToolTipText("在使用只狼NPC原Flver文件时，可以通过修改Unk18参数来使多张贴图正确显示");

		listModel = new DefaultListModel<>();
		materialTypeList = new JXList(listModel);

		add(new JXLabel("匹配："), "span");
		add(materialFileLabel, "span, split 3");
		add(materialFileField);
		add(materialFileButton);
		add(reLabel, "span, split 3");
		add(reField);
		add(reButton);
		JScrollPane scrollPane = new JScrollPane(materialTypeList);
		scrollPane.setBorder(null);
		add(scrollPane, "span, growx, h 300::");
		add(new JXLabel("功能："), "span");
		add(replaceAllCheckBox, "span, split 3");
		add(replaceAllLabel);
		add(replaceAllField);
		add(setUnk18CheckBox, "span, split 2");
		add(setUnk18Label);
		add(okButton, "span,center");
		add(Box.createVerticalStrut(24), "span");
		add(saveButton, "span, center");
	}

	private void initListener() {
		replaceAllCheckBox.addItemListener(e -> {
			if (e.getStateChange() == ItemEvent.SELECTED) {
				replaceAllField.setEnabled(true);
				replaceAllLabel.setEnabled(true);
			} else {
				replaceAllLabel.setEnabled(false);
				replaceAllField.setEnabled(false);
			}
		});
		setUnk18CheckBox.addItemListener(e -> setUnk18Label.setEnabled(e.getStateChange() == ItemEvent.SELECTED));

		// 输入框内容修改时修改状态
		materialFileField.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void insertUpdate(DocumentEvent e) {
				isUpdated = true;
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				isUpdated = true;
			}

			@Override
			public void changedUpdate(DocumentEvent e) {

			}
		});

		addAncestorListener(new AncestorListener() {
			@Override
			public void ancestorAdded(AncestorEvent event) {
				materialFileField.setText(RoleSession.MATERIAL_PATH);
				isUpdated = true;
			}

			@Override
			public void ancestorRemoved(AncestorEvent event) {
				BaseSession.setVal(RoleSession.class, "MATERIAL_PATH", materialFileField.getText());
			}

			@Override
			public void ancestorMoved(AncestorEvent event) {

			}
		});

		// 选择JSON文件
		materialFileButton.addActionListener(e -> {
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
			fileChooser.setFileFilter(new FileFilter() {
				@Override
				public boolean accept(File f) {
					return f.getName().endsWith(".json");
				}

				@Override
				public String getDescription() {
					return null;
				}
			});
			if (fileChooser.showOpenDialog(EZEnvironment.getParentFrame()) == JFileChooser.APPROVE_OPTION) {
				String newVal = fileChooser.getSelectedFile().getAbsolutePath();
				materialFileField.setText(newVal);
				isUpdated = true;
				BaseSession.setVal(RoleSession.class, "MATERIAL_PATH", newVal);
			}
		});

		// 匹配正则表达式
		reButton.addActionListener(e -> {
			String re = reField.getText();
			Pattern p = Pattern.compile(re);

			// 解析，如果已经解析过就使用内存中数据
			if (isUpdated || materialJsons == null) {
				File file = new File(materialFileField.getText());
				if (!file.isFile()) {
					JOptionPane.showConfirmDialog(EZEnvironment.getParentFrame(),
							materialFileField.getText() + "文件不存在", "提示", JOptionPane.DEFAULT_OPTION);
					return;
				}

				try {
					materialJsons = MaterialDataUtil.parseMaterialFile(file);
				} catch (Exception ex) {
					JOptionPane.showConfirmDialog(EZEnvironment.getParentFrame(),
							"文件解析失败，失败原因为：" + ex.getMessage(), "提示", JOptionPane.DEFAULT_OPTION);
					return;
				}
			}

			// 替换list
			List<String> texturesNameList = materialJsons.stream()
					.map(materialJson -> p.matcher(materialJson.getName()).find()
							? materialJson.getName() + "(MTD: " + materialJson.getMTD() + ")"
							: null) //这里认定不会有重复的材质名
					.filter(Objects::nonNull)
					.toList();
			listModel.clear();
			listModel.addAll(texturesNameList);
			isUpdated = false;
		});

		// 替换
		okButton.addActionListener(e -> {
			if (!replaceAllCheckBox.isSelected() && !setUnk18CheckBox.isSelected()) {
				JOptionPane.showConfirmDialog(EZEnvironment.getParentFrame(), "请勾选一项再开始", "提示", JOptionPane.DEFAULT_OPTION);
				return;
			}

			String newMTD = replaceAllField.getText();

			// 检查是否需要更新列表
			if (isUpdated)
				reButton.doClick();

			// unk18不能重复，这里定义逐渐递减也不会重复的最小unk18
			int currentUnk18 = 999;
			for (MaterialJson materialJson : materialJsons) {
				if (materialJson.getUnk18() + materialJsons.size() > currentUnk18)
					currentUnk18 = materialJson.getUnk18() + materialJsons.size();
			}

			// 提取列表材质名
			HashSet<String> set = new HashSet<>();
			Pattern p = Pattern.compile("^(.+)\\(MTD: .+\\)$"); //把材质名提取出来
			for (int i = 0; i < listModel.getSize(); i++) {
				String s = listModel.getElementAt(i);
				Matcher matcher = p.matcher(s);
				if (matcher.find())
					set.add(matcher.group(1));
			}

			// 更新内存数据
			for (MaterialJson materialJson : materialJsons) {
				if (set.contains(materialJson.getName())) {
					if (replaceAllCheckBox.isSelected())
						materialJson.setMTD(newMTD);
					if (setUnk18CheckBox.isSelected())
						materialJson.setUnk18(currentUnk18--);
				}
			}

			// 更新表格
			reButton.doClick();
		});

		saveButton.addActionListener(e -> {
			// 写出
			File file = new File(materialFileField.getText());
			try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, StandardCharsets.UTF_8))) {
				bw.write(JSON.toJSONString(materialJsons));
				JOptionPane.showConfirmDialog(EZEnvironment.getParentFrame(), "文件保存成功！", "提示", JOptionPane.DEFAULT_OPTION);
			} catch (IOException e2) {
				JOptionPane.showConfirmDialog(EZEnvironment.getParentFrame(),
						"文件保存失败，原因为：" + e2.getMessage(), "提示", JOptionPane.DEFAULT_OPTION);
			}
		});

	}
}
